﻿/*
 * 2021.03.27-Code rectification and function enhancement.
 *            Huawei Device Co., Ltd. <mobile@huawei.com>
 */

#include "../StdAfx.h"
#include "../Debug/LogOut.h"

namespace DuiLib {
IMPLEMENT_DUICONTROL(CContainerUI)

CContainerUI::CContainerUI()
    : m_iChildPadding(0),
      m_iChildAlign(DT_LEFT),
      m_iChildVAlign(DT_TOP),
      m_bAutoDestroy(true),
      m_bDelayedDestroy(true),
      m_bMouseChildEnabled(true),
      m_pVerticalScrollBar(nullptr),
      m_pHorizontalScrollBar(nullptr),
      m_nScrollStepSize(0),
      m_downScrollPos {0, 0},
      m_downPointer{0, 0}
{
    (void)::SecureZeroMemory(&m_rcInset, sizeof(m_rcInset));
    (void)::SecureZeroMemory(&m_rcScrollBarPadding, sizeof(m_rcScrollBarPadding));
}

CContainerUI::~CContainerUI()
{
    m_bDelayedDestroy = false;
    RemoveAll();
    if (m_pVerticalScrollBar) {
        delete m_pVerticalScrollBar;
        m_pVerticalScrollBar = nullptr;
    }
    if (m_pHorizontalScrollBar) {
        delete m_pHorizontalScrollBar;
        m_pHorizontalScrollBar = nullptr;
    }
}

void CContainerUI::SetCustomScrollBar(ICustomScrollBar *customScrollBar)
{
    this->customScrollBar = customScrollBar;
}

LPCTSTR CContainerUI::GetClass() const
{
    return _T("ContainerUI");
}

LPVOID CContainerUI::GetInterface(LPCTSTR pstrName)
{
    if (_tcsicmp(pstrName, _T("IContainer")) == 0) {
        return static_cast<IContainerUI *>(this);
    } else if (_tcsicmp(pstrName, DUI_CTR_CONTAINER) == 0) {
        return static_cast<CContainerUI *>(this);
    }
    return CControlUI::GetInterface(pstrName);
}

CControlUI *CContainerUI::GetItemAt(int iIndex)
{
    if (iIndex < 0 || iIndex >= m_items.GetSize()) {
        return nullptr;
    }
    return static_cast<CControlUI *>(m_items.GetAt(iIndex));
}

int CContainerUI::GetItemIndex(CControlUI *pControl)
{
    for (int it = 0; it < m_items.GetSize(); it++) {
        if (static_cast<CControlUI *>(m_items.GetAt(it)) == pControl) {
            return it;
        }
    }

    return -1;
}

bool CContainerUI::SetItemIndex(CControlUI *pControl, int iIndex)
{
    for (int it = 0; it < m_items.GetSize(); it++) {
        if (static_cast<CControlUI *>(m_items.GetAt(it)) == pControl) {
            NeedUpdate();
            m_items.Remove(it);
            return m_items.InsertAt(iIndex, pControl);
        }
    }

    return false;
}

int CContainerUI::GetCount()
{
    return m_items.GetSize();
}

void CContainerUI::SetScrollBarPadding(const RECT &rc)
{
    m_rcScrollBarPadding = rc;
}

bool CContainerUI::Add(CControlUI *pControl)
{
    if (pControl == nullptr) {
        return false;
    }

    if (!CPaintManagerUI::IsMainThread()) {
        LOG_ERROR("[DUILIB]Cannot invoke CContainerUI::Add() outside ui thread");
    }

    if (m_pManager != nullptr) {
        m_pManager->InitControls(pControl, this);
    }
    if (IsVisible()) {
        NeedUpdate();
    } else {
        pControl->SetInternVisible(false);
    }
    return m_items.Add(pControl);
}

bool CContainerUI::AddAt(CControlUI *pControl, int iIndex)
{
    if (pControl == nullptr) {
        return false;
    }

    if (!CPaintManagerUI::IsMainThread()) {
        wstring temp;
        if (GetName().GetData()) {
            temp = GetName().GetData();
        }
        LOG_ERROR((L"[DUILIB]Cannot invoke CContainerUI::AddAt() outside ui thread " + temp).c_str());
    }

    if (m_pManager != nullptr) {
        m_pManager->InitControls(pControl, this);
    }
    if (IsVisible()) {
        NeedUpdate();
    } else {
        pControl->SetInternVisible(false);
    }
    return m_items.InsertAt(iIndex, pControl);
}

bool CContainerUI::Remove(CControlUI *pControl)
{
    if (pControl == nullptr) {
        return false;
    }

    if (!CPaintManagerUI::IsMainThread()) {
        wstring temp;
        if (GetName().GetData()) {
            temp = GetName().GetData();
        }
        LOG_ERROR((L"[DUILIB]Cannot invoke CContainerUI::Remove outside ui thread " + temp).c_str());
    }

    for (int it = 0; it < m_items.GetSize(); it++) {
        if (static_cast<CControlUI *>(m_items.GetAt(it)) == pControl) {
            NeedUpdate();
            if (m_bAutoDestroy) {
                if (m_bDelayedDestroy && m_pManager) {
                    m_pManager->AddDelayedCleanup(pControl);
                } else {
                    delete pControl;
                }
            }
            return m_items.Remove(it);
        }
    }
    return false;
}

bool CContainerUI::RemoveAt(int iIndex)
{
    if (!CPaintManagerUI::IsMainThread()) {
        wstring temp;
        if (GetName().GetData()) {
            temp = GetName().GetData();
        }
        LOG_ERROR((L"[DUILIB]Cannot invoke CContainerUI::RemoveAt() outside ui thread " + temp).c_str());
    }

    CControlUI *pControl = GetItemAt(iIndex);
    if (pControl != nullptr) {
        return CContainerUI::Remove(pControl);
    }

    return false;
}

void CContainerUI::RemoveAll()
{
    if (!CPaintManagerUI::IsMainThread()) {
        wstring temp;
        if (GetName().GetData()) {
            temp = GetName().GetData();
        }
        LOG_ERROR((L"[DUILIB]Cannot invoke CContainerUI::RemoveAll() outside ui thread " + temp).c_str());
    }

    for (int it = 0; m_bAutoDestroy && it < m_items.GetSize(); it++) {
        CControlUI *pItem = static_cast<CControlUI *>(m_items.GetAt(it));
        if (pItem == nullptr) {
            continue;
        }
        if (m_bDelayedDestroy && m_pManager) {
            m_pManager->AddDelayedCleanup(pItem);
        } else {
            delete pItem;
            pItem = nullptr;
        }
    }
    m_items.Empty();
    NeedUpdate();
}

bool CContainerUI::IsAutoDestroy() const
{
    return m_bAutoDestroy;
}

void CContainerUI::SetAutoDestroy(bool bAuto)
{
    m_bAutoDestroy = bAuto;
}

bool CContainerUI::IsDelayedDestroy() const
{
    return m_bDelayedDestroy;
}

void CContainerUI::SetDelayedDestroy(bool bDelayed)
{
    m_bDelayedDestroy = bDelayed;
}

RECT CContainerUI::GetInset() const
{
    if (m_rcInset.left > 1 || m_rcInset.top > 1 || m_rcInset.right > 1 || m_rcInset.bottom > 1) {
        if (m_pManager != nullptr) {
            return CResourceManager::GetInstance()->Scale(*m_pManager, m_rcInset);
        }
    }
    return m_rcInset;
}

void CContainerUI::SetInset(RECT rcInset)
{
    m_rcInset = rcInset;
    NeedUpdate();
}

int CContainerUI::GetChildPadding() const
{
    return m_pManager == nullptr ? m_iChildPadding :
        CResourceManager::GetInstance()->Scale(*m_pManager, m_iChildPadding);
}

void CContainerUI::SetChildPadding(int iPadding)
{
    m_iChildPadding = iPadding;
    NeedUpdate();
}

UINT CContainerUI::GetChildAlign() const
{
    return m_iChildAlign;
}

void CContainerUI::SetChildAlign(UINT iAlign)
{
    m_iChildAlign = iAlign;
    NeedUpdate();
}

UINT CContainerUI::GetChildVAlign() const
{
    return m_iChildVAlign;
}

void CContainerUI::SetChildVAlign(UINT iVAlign)
{
    m_iChildVAlign = iVAlign;
    NeedUpdate();
}

bool CContainerUI::IsMouseChildEnabled() const
{
    return m_bMouseChildEnabled;
}

void CContainerUI::SetMouseChildEnabled(bool bEnable)
{
    m_bMouseChildEnabled = bEnable;
}

void CContainerUI::SetVisible(bool bVisible)
{
    if (m_bVisible == bVisible) {
        return;
    }
    CControlUI::SetVisible(bVisible);
    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
        if (item1 == nullptr) {
            continue;
        }
        item1->SetInternVisible(IsVisible());
    }
}

// 逻辑上，对于Container控件不公开此方法
// 调用此方法的结果是，内部子控件隐藏，控件本身依然显示，背景等效果存在
void CContainerUI::SetInternVisible(bool bVisible)
{
    CControlUI::SetInternVisible(bVisible);
    if (m_items.IsEmpty()) {
        return;
    }
    for (int it = 0; it < m_items.GetSize(); it++) {
        // 控制子控件显示状态
        // InternVisible状态应由子控件自己控制
        CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
        if (item1 == nullptr) {
            continue;
        }
        item1->SetInternVisible(IsVisible());
    }
}

void CContainerUI::SetEnabled(bool bEnabled)
{
    if (m_bEnabled == bEnabled) {
        return;
    }

    m_bEnabled = bEnabled;

    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
        if (item1 == nullptr) {
            continue;
        }
        item1->SetEnabled(m_bEnabled);
    }

    Invalidate();
}

void CContainerUI::SetMouseEnabled(bool bEnabled)
{
    if (m_pVerticalScrollBar != nullptr) {
        m_pVerticalScrollBar->SetMouseEnabled(bEnabled);
    }
    if (m_pHorizontalScrollBar != nullptr) {
        m_pHorizontalScrollBar->SetMouseEnabled(bEnabled);
    }
    CControlUI::SetMouseEnabled(bEnabled);
}

void CContainerUI::DoEvent(TEventUI &event)
{
    if (!IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND) {
        if (m_pParent != nullptr) {
            m_pParent->DoEvent(event);
        } else {
            CControlUI::DoEvent(event);
        }
        return;
    }
    FocusTreat(event);

    VScrollTreat(event);

    HScrollTreat(event);
    CControlUI::DoEvent(event);
}

void CContainerUI::FocusTreat(TEventUI &event)
{
    if (event.Type == UIEVENT_SETFOCUS) {
        m_bFocused = true;
        // add event by fjj
        if (m_pManager) {
            m_pManager->SendNotify(this, DUI_MSGTYPE_SETFOCUS);
        }
        return;
    }
    if (event.Type == UIEVENT_KILLFOCUS) {
        m_bFocused = false;
        // add event by fjj
        if (m_pManager) {
            m_pManager->SendNotify(this, DUI_MSGTYPE_KILLFOCUS);
        }
        return;
    }
}

void CContainerUI::HScrollTreat(TEventUI &event)
{
    if (IsScrollValid(m_pHorizontalScrollBar)) {
        if (event.Type == UIEVENT_KEYDOWN) {
            switch (event.chKey) {
                case VK_DOWN:
                    LineRight();
                    return;
                case VK_UP:
                    LineLeft();
                    return;
                case VK_NEXT:
                    PageRight();
                    return;
                case VK_PRIOR:
                    PageLeft();
                    return;
                case VK_HOME:
                    HomeLeft();
                    return;
                case VK_END:
                    EndRight();
                    return;
            }
        } else if (event.Type == UIEVENT_SCROLLWHEEL) {
            switch (LOWORD(event.wParam)) {
                case SB_LINEUP:
                    LineLeft();
                    return;
                case SB_LINEDOWN:
                    LineRight();
                    return;
            }
        }
    }
}

void CContainerUI::VScrollTreat(TEventUI &event)
{
    if (IsScrollValid(m_pVerticalScrollBar)) {
        if (event.Type == UIEVENT_KEYDOWN) {
            switch (event.chKey) {
                case VK_DOWN:
                    LineDown();
                    return;
                case VK_UP:
                    LineUp();
                    return;
                case VK_NEXT:
                    PageDown();
                    return;
                case VK_PRIOR:
                    PageUp();
                    return;
                case VK_HOME:
                    HomeUp();
                    return;
                case VK_END:
                    EndDown();
                    return;
            }
        } else if (event.Type == UIEVENT_SCROLLWHEEL) {
            switch (LOWORD(event.wParam)) {
                case SB_LINEUP:
                    if (!mouseWheelUpMsgFilter.Triger()) {
                        return;
                    }
                    LineUp();
                    return;
                case SB_LINEDOWN:
                    if (!mouseWheelDownMsgFilter.Triger()) {
                        return;
                    }
                    LineDown();
                    return;
            }
        } else if (event.Type == UIEVENT_POINTERDOWN) {
            m_downPointer = event.ptMouse;
            m_downScrollPos = GetScrollPos();
            return;
        } else if (event.Type == UIEVENT_POINTERUPDATE) {
            SIZE sz = m_downScrollPos;
            sz.cy -= event.ptMouse.y - m_downPointer.y;
            SetScrollPos(sz);

            ::PostMessage(m_pManager->GetPaintWindow(), WM_PAINT, 0, 0);
        }
    }
}

bool CContainerUI::IsScrollValid(CScrollBarUI *scrollBar)
{
    return scrollBar != nullptr && scrollBar->IsVisible() && scrollBar->IsEnabled();
}

SIZE CContainerUI::GetScrollPos() const
{
    SIZE sz = { 0, 0 };
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        sz.cy = m_pVerticalScrollBar->GetScrollPos();
    }
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        sz.cx = m_pHorizontalScrollBar->GetScrollPos();
    }
    return sz;
}

SIZE CContainerUI::GetScrollRange() const
{
    SIZE sz = { 0, 0 };
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        sz.cy = m_pVerticalScrollBar->GetScrollRange();
    }
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        sz.cx = m_pHorizontalScrollBar->GetScrollRange();
    }
    return sz;
}

void CContainerUI::SetScrollPos(SIZE szPos, bool bMsg)
{
    if (customScrollBar) {
        if (customScrollBar->SetScrollPos(this, szPos, bMsg)) {
            return;
        }
    }

    int cx = 0;
    int cy = 0;
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        int iLastScrollPos = m_pVerticalScrollBar->GetScrollPos();
        m_pVerticalScrollBar->SetScrollPos(szPos.cy);
        cy = m_pVerticalScrollBar->GetScrollPos() - iLastScrollPos;
    }

    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        int iLastScrollPos = m_pHorizontalScrollBar->GetScrollPos();
        m_pHorizontalScrollBar->SetScrollPos(szPos.cx);
        cx = m_pHorizontalScrollBar->GetScrollPos() - iLastScrollPos;
    }

    if (cx == 0 && cy == 0) {
        return;
    }

    RECT rcPos;
    for (int it2 = 0; it2 < m_items.GetSize(); it2++) {
        CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it2));
        if (pControl == nullptr) {
            continue;
        }
        if (!pControl->IsVisible()) {
            continue;
        }
        if (pControl->IsFloat()) {
            continue;
        }

        rcPos = pControl->GetPos();
        rcPos.left -= cx;
        rcPos.right -= cx;
        rcPos.top -= cy;
        rcPos.bottom -= cy;
        pControl->SetPos(rcPos);
    }

    Invalidate();

    if (m_pVerticalScrollBar) {
        // 发送滚动消息
        if (m_pManager != nullptr && bMsg) {
            int nPage = (m_pVerticalScrollBar->GetScrollPos() + m_pVerticalScrollBar->GetLineSize()) /
                m_pVerticalScrollBar->GetLineSize();
            m_pManager->SendNotify(this, DUI_MSGTYPE_SCROLL, (WPARAM)nPage);
        }
    }
}

void CContainerUI::SetScrollStepSize(int nSize)
{
    if (nSize > 0) {
        m_nScrollStepSize = nSize;
    }
}

int CContainerUI::GetScrollStepSize() const
{
    return m_pManager == nullptr ? m_nScrollStepSize :
        CResourceManager::GetInstance()->Scale(*m_pManager, m_nScrollStepSize);
}

void CContainerUI::PointerUp()
{
    const int step = 12;
    SIZE sz = GetScrollPos();
    sz.cy -= step;
    SetScrollPos(sz);
}

void CContainerUI::PointerDown()
{
    const int step = 12;
    SIZE sz = GetScrollPos();
    sz.cy += step;
    SetScrollPos(sz);
}
void CContainerUI::LineUp()
{
    const int lineValue = 8;
    const int lineMul = 4;
    int cyLine = m_nScrollStepSize;
    if (m_nScrollStepSize == 0) {
        cyLine = lineValue;
        if (m_pManager != nullptr && m_pManager->GetDefaultFontInfo() != nullptr) {
            if (m_pManager->GetDefaultFontInfo()->tm.tmHeight > INT_MAX / lineMul) {
                return;
            }
            cyLine = (m_pManager->GetDefaultFontInfo()->tm.tmHeight) * lineMul;
        }
    }

    SIZE sz = GetScrollPos();
    sz.cy -= cyLine;
    SetScrollPos(sz);
}

void CContainerUI::LineDown()
{
    const int lineValue = 8;
    const int lineMul = 4;
    int cyLine = m_nScrollStepSize;
    if (m_nScrollStepSize == 0) {
        cyLine = lineValue;
        if (m_pManager != nullptr && m_pManager->GetDefaultFontInfo() != nullptr) {
            if (m_pManager->GetDefaultFontInfo()->tm.tmHeight > LONG_MAX / lineMul) {
                return;
            }

            cyLine = (m_pManager->GetDefaultFontInfo()->tm.tmHeight) * lineMul;
        }
    }

    SIZE sz = GetScrollPos();
    sz.cy += cyLine;
    SetScrollPos(sz);
}

void CContainerUI::PageUp()
{
    SIZE sz = GetScrollPos();
    int iOffset = m_rcItem.bottom - m_rcItem.top - GetInset().top - GetInset().bottom;
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        iOffset -= m_pHorizontalScrollBar->GetFixedHeight();
    }
    sz.cy -= iOffset;
    SetScrollPos(sz);
}

void CContainerUI::PageDown()
{
    SIZE sz = GetScrollPos();
    int iOffset = m_rcItem.bottom - m_rcItem.top - GetInset().top - GetInset().bottom;
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        iOffset -= m_pHorizontalScrollBar->GetFixedHeight();
    }
    sz.cy += iOffset;
    SetScrollPos(sz);
}

void CContainerUI::HomeUp()
{
    SIZE sz = GetScrollPos();
    sz.cy = 0;
    SetScrollPos(sz);
}

void CContainerUI::EndDown()
{
    SIZE sz = GetScrollPos();
    sz.cy = GetScrollRange().cy;
    SetScrollPos(sz);
}

void CContainerUI::LineLeft()
{
    const int lineValue = 8;
    int cxLine = m_nScrollStepSize == 0 ? lineValue : m_nScrollStepSize;

    SIZE sz = GetScrollPos();
    sz.cx -= cxLine;
    SetScrollPos(sz);
}

void CContainerUI::LineRight()
{
    const int lineValue = 8;
    int cxLine = m_nScrollStepSize == 0 ? lineValue : m_nScrollStepSize;

    SIZE sz = GetScrollPos();
    sz.cx += cxLine;
    SetScrollPos(sz);
}

void CContainerUI::PageLeft()
{
    SIZE sz = GetScrollPos();
    int iOffset = m_rcItem.right - m_rcItem.left - GetInset().left - GetInset().right;
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        iOffset -= m_pVerticalScrollBar->GetFixedWidth();
    }
    sz.cx -= iOffset;
    SetScrollPos(sz);
}

void CContainerUI::PageRight()
{
    SIZE sz = GetScrollPos();
    int iOffset = m_rcItem.right - m_rcItem.left - GetInset().left - GetInset().right;
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        iOffset -= m_pVerticalScrollBar->GetFixedWidth();
    }
    sz.cx += iOffset;
    SetScrollPos(sz);
}

void CContainerUI::HomeLeft()
{
    SIZE sz = GetScrollPos();
    sz.cx = 0;
    SetScrollPos(sz);
}

void CContainerUI::EndRight()
{
    SIZE sz = GetScrollPos();
    sz.cx = GetScrollRange().cx;
    SetScrollPos(sz);
}

void CContainerUI::EnableScrollBar(bool bEnableVertical, bool bEnableHorizontal)
{
    if (bEnableVertical && !m_pVerticalScrollBar) {
        m_pVerticalScrollBar = new (std::nothrow) CScrollBarUI;
        if (m_pVerticalScrollBar == nullptr) {
            return;
        }
        m_pVerticalScrollBar->SetOwner(this);
        m_pVerticalScrollBar->SetManager(m_pManager, this, m_pManager != nullptr);
        if (m_pManager) {
            LPCTSTR pDefaultAttributes = m_pManager->GetDefaultAttributeList(_T("VScrollBar"));
            if (pDefaultAttributes) {
                m_pVerticalScrollBar->ApplyAttributeList(pDefaultAttributes);
            }
        }
    } else if (!bEnableVertical && m_pVerticalScrollBar) {
        delete m_pVerticalScrollBar;
        m_pVerticalScrollBar = nullptr;
    }

    if (bEnableHorizontal && !m_pHorizontalScrollBar) {
        m_pHorizontalScrollBar = new (std::nothrow) CScrollBarUI ;
        if (m_pHorizontalScrollBar == nullptr) {
            return;
        }
        m_pHorizontalScrollBar->SetHorizontal(true);
        m_pHorizontalScrollBar->SetOwner(this);
        m_pHorizontalScrollBar->SetManager(m_pManager, nullptr, false);

        if (m_pManager) {
            LPCTSTR pDefaultAttributes = m_pManager->GetDefaultAttributeList(_T("HScrollBar"));
            if (pDefaultAttributes) {
                m_pHorizontalScrollBar->ApplyAttributeList(pDefaultAttributes);
            }
        }
    } else if (!bEnableHorizontal && m_pHorizontalScrollBar) {
        delete m_pHorizontalScrollBar;
        m_pHorizontalScrollBar = nullptr;
    }

    NeedUpdate();
}

CScrollBarUI *CContainerUI::GetVerticalScrollBar() const
{
    return m_pVerticalScrollBar;
}

CScrollBarUI *CContainerUI::GetHorizontalScrollBar() const
{
    return m_pHorizontalScrollBar;
}

void CContainerUI::SetOpacity(int n)
{
    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
        if (pControl != nullptr) {
            pControl->SetOpacity(n);
        }
    }

    m_nOpacity = n;
    Invalidate();
}

void CContainerUI::SetBlur(int n)
{
    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
        if (pControl != nullptr) {
            pControl->SetBlur(n);
        }
    }

    m_nBlur = n;
}

int CContainerUI::FindSelectable(int iIndex, bool bForward)
{
    // NOTE: This is actually a helper-function for the list/combo/ect controls
    //       that allow them to find the next enabled/available selectable item
    if (GetCount() == 0) {
        return -1;
    }
    iIndex = CLAMP(iIndex, 0, GetCount() - 1);
    if (bForward) {
        for (int i = iIndex; i < GetCount(); i++) {
            CControlUI *item = GetItemAt(i);
            if (item && item->GetInterface(_T("ListItem")) != nullptr && item->IsVisible() && item->IsEnabled()) {
                return i;
            }
        }
        return -1;
    } else {
        for (int i = iIndex; i >= 0; --i) {
            // Null pointer dereferences, Dereference null return (stat)
            CControlUI *item1 = GetItemAt(i);

            if (item1 == nullptr) {
                continue;
            }

            if (item1->GetInterface(L"ListItem") == nullptr) {
                continue;
            }

            if (item1->IsVisible() && item1->IsEnabled()) {
                return i;
            }
        }
        return FindSelectable(0, true);
    }
}

RECT CContainerUI::GetClientPos() const
{
    RECT rc = m_rcItem;
    rc.left += GetInset().left;
    rc.top += GetInset().top;
    rc.right -= GetInset().right;
    rc.bottom -= GetInset().bottom;

    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        rc.top -= m_pVerticalScrollBar->GetScrollPos();
        rc.bottom -= m_pVerticalScrollBar->GetScrollPos();
        rc.bottom += m_pVerticalScrollBar->GetScrollRange();
        rc.right -= m_pVerticalScrollBar->GetFixedWidth();
    }
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        rc.left -= m_pHorizontalScrollBar->GetScrollPos();
        rc.right -= m_pHorizontalScrollBar->GetScrollPos();
        rc.right += m_pHorizontalScrollBar->GetScrollRange();
        rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
    }
    return rc;
}

void CContainerUI::Move(SIZE szOffset, bool bNeedInvalidate)
{
    CControlUI::Move(szOffset, bNeedInvalidate);
    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        m_pVerticalScrollBar->Move(szOffset, false);
    }
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        m_pHorizontalScrollBar->Move(szOffset, false);
    }
    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
        if (pControl == nullptr) {
            continue;
        }
        if (pControl != nullptr && pControl->IsVisible()) {
            pControl->Move(szOffset, false);
        }
    }
}

bool CContainerUI::IsAutoHeightContainer()
{
    CPaintManagerUI* manager = GetManager();
    if (manager == nullptr || !manager->GetAutoWndHeightStatus()) {
        return false;
    }
    if (static_cast<CControlUI*>(this) == manager->GetRoot()) {
        for (int i = 0; i < GetCount(); i++) {
            CControlUI* childCtrl = GetItemAt(i);
            if (childCtrl == nullptr) {
                continue;
            }
            if (childCtrl->IsFloat()) { // 不支持float子元素
                return false;
            }
            // 子元素既不固定高度，也不是自适应高度control，则窗口自适应高度失效
            if (childCtrl->GetFixedHeight() == 0 && !childCtrl->GetAutoHeightCtrl()) {
                return false;
            }
        }
        return true;
    }
    return false;
}

void CContainerUI::ChangeWndAutoHeight(int newHeight)
{
    CPaintManagerUI* manager = GetManager();
    if (manager != nullptr) {
        bool heightChanged = manager->SetRefreshedAutoHeight(newHeight);
        int dwHeight = manager->GetRefreshedAutoHeight();
        int originWndX = manager->GetFixOrgiSize().cx;
        if (heightChanged) {
            ::SetWindowPos(manager->m_hWndPaint, nullptr, 0, 0, originWndX, dwHeight, SWP_NOZORDER |
                SWP_NOMOVE | SWP_NOACTIVATE);
            ::UpdateWindow(manager->m_hWndPaint);
            ::SendMessage(manager->GetPaintWindow(), WM_APP + AUTO_WND_HEIGHT_CHANGED,
                reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(nullptr));
        }
    }
}

void CContainerUI::SetPos(RECT rc, bool bNeedInvalidate)
{
    CControlUI::SetPos(rc, bNeedInvalidate);
    if (m_items.IsEmpty()) {
        return;
    }

    rc = m_rcItem;
    rc.left += GetInset().left;
    rc.top += GetInset().top;
    rc.right -= GetInset().right;
    rc.bottom -= GetInset().bottom;

    if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
        rc.top -= m_pVerticalScrollBar->GetScrollPos();
        rc.bottom -= m_pVerticalScrollBar->GetScrollPos();
        rc.bottom += m_pVerticalScrollBar->GetScrollRange();
        rc.right -= m_pVerticalScrollBar->GetFixedWidth();
    }
    if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
        rc.left -= m_pHorizontalScrollBar->GetScrollPos();
        rc.right -= m_pHorizontalScrollBar->GetScrollPos();
        rc.right += m_pHorizontalScrollBar->GetScrollRange();
        rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
    }

    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
        if (pControl == nullptr) {
            continue;
        }
        if (!pControl->IsVisible()) {
            continue;
        }
        if (pControl->IsFloat()) {
            SetFloatPos(it);
        } else {
            SIZE sz = { rc.right - rc.left, rc.bottom - rc.top };
            if (sz.cx < pControl->GetMinWidth()) {
                sz.cx = pControl->GetMinWidth();
            }
            if (sz.cx > pControl->GetMaxWidth()) {
                sz.cx = pControl->GetMaxWidth();
            }
            if (sz.cy < pControl->GetMinHeight()) {
                sz.cy = pControl->GetMinHeight();
            }
            if (sz.cy > pControl->GetMaxHeight()) {
                sz.cy = pControl->GetMaxHeight();
            }
            RECT rcCtrl = { rc.left, rc.top, rc.left + sz.cx, rc.top + sz.cy };
            pControl->SetPos(rcCtrl, false);
        }
    }
}

void CContainerUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
    const int radixValue = 10;
    if (_tcsicmp(pstrName, _T("inset")) == 0) {
        RECT rcInset = { 0 };
        LPTSTR pstr = nullptr;
        rcInset.left = _tcstol(pstrValue, &pstr, radixValue);
        ASSERT(pstr);
        rcInset.top = _tcstol(pstr + 1, &pstr, radixValue);
        ASSERT(pstr);
        rcInset.right = _tcstol(pstr + 1, &pstr, radixValue);
        ASSERT(pstr);
        rcInset.bottom = _tcstol(pstr + 1, &pstr, radixValue);
        ASSERT(pstr);
        SetInset(rcInset);
    } else if (_tcsicmp(pstrName, _T("opacity")) == 0) {
        SetOpacity(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("blur")) == 0) {
        SetBlur(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("mousechild")) == 0) {
        SetMouseChildEnabled(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("vscrollbar")) == 0) {
        EnableScrollBar(_tcsicmp(pstrValue, _T("true")) == 0, GetHorizontalScrollBar() != nullptr);
    } else if (_tcsicmp(pstrName, _T("vscrollbarstyle")) == 0) {
        m_sVerticalScrollBarStyle = pstrValue;
        EnableScrollBar(TRUE, GetHorizontalScrollBar() != nullptr);
        if (GetVerticalScrollBar()) {
            LPCTSTR pStyle = m_pManager->GetStyle(m_sVerticalScrollBarStyle);
            if (pStyle) {
                GetVerticalScrollBar()->ApplyAttributeList(pStyle);
            } else {
                GetVerticalScrollBar()->ApplyAttributeList(pstrValue);
            }
        }
    } else if (_tcsicmp(pstrName, _T("hscrollbar")) == 0) {
        EnableScrollBar(GetVerticalScrollBar() != nullptr, _tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("hscrollbarstyle")) == 0) {
        m_sHorizontalScrollBarStyle = pstrValue;
        EnableScrollBar(TRUE, GetHorizontalScrollBar() != nullptr);
        if (GetHorizontalScrollBar()) {
            LPCTSTR pStyle = m_pManager->GetStyle(m_sHorizontalScrollBarStyle);
            if (pStyle) {
                GetHorizontalScrollBar()->ApplyAttributeList(pStyle);
            } else {
                GetHorizontalScrollBar()->ApplyAttributeList(pstrValue);
            }
        }
    } else if (_tcsicmp(pstrName, _T("childpadding")) == 0) {
        SetChildPadding(_ttoi(pstrValue));
    } else if (_tcscmp(pstrName, _T("childalign")) == 0) {
        if (_tcscmp(pstrValue, _T("left")) == 0) {
            m_iChildAlign = DT_LEFT;
        } else if (_tcscmp(pstrValue, _T("center")) == 0) {
            m_iChildAlign = DT_CENTER;
        } else if (_tcscmp(pstrValue, _T("right")) == 0) {
            m_iChildAlign = DT_RIGHT;
        }
    } else if (_tcscmp(pstrName, _T("childvalign")) == 0) {
        if (_tcscmp(pstrValue, _T("top")) == 0) {
            m_iChildVAlign = DT_TOP;
        } else if (_tcscmp(pstrValue, _T("vcenter")) == 0) {
            m_iChildVAlign = DT_VCENTER;
        } else if (_tcscmp(pstrValue, _T("bottom")) == 0) {
            m_iChildVAlign = DT_BOTTOM;
        }
    } else if (_tcsicmp(pstrName, _T("scrollstepsize")) == 0) {
        SetScrollStepSize(_ttoi(pstrValue));
    } else {
        CControlUI::SetAttribute(pstrName, pstrValue);
    }
}

void CContainerUI::SetManager(CPaintManagerUI *pManager, CControlUI *pParent, bool bInit)
{
    for (int it = 0; it < m_items.GetSize(); it++) {
        CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
        if (item1 == nullptr) {
            continue;
        }
        item1->SetManager(pManager, this, bInit);
    }

    if (m_pVerticalScrollBar != nullptr) {
        m_pVerticalScrollBar->SetManager(pManager, this, bInit);
    }
    if (m_pHorizontalScrollBar != nullptr) {
        m_pHorizontalScrollBar->SetManager(pManager, this, bInit);
    }
    CControlUI::SetManager(pManager, pParent, bInit);
}

CControlUI *CContainerUI::FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags)
{
    if ((uFlags & UIFIND_VISIBLE) != 0 && !IsVisible()) {
        return nullptr;
    }
    if ((uFlags & UIFIND_ENABLED) != 0 && !IsEnabled()) {
        return nullptr;
    }
    if ((uFlags & UIFIND_HITTEST) != 0 && !::PtInRect(&m_rcItem, *(static_cast<LPPOINT>(pData)))) {
        return nullptr;
    }
    if ((uFlags & UIFIND_UPDATETEST) != 0 && Proc(this, pData) != nullptr) {
        return nullptr;
    }

    CControlUI *pResult = nullptr;
    if ((uFlags & UIFIND_ME_FIRST) != 0) {
        if ((uFlags & UIFIND_HITTEST) == 0 || IsMouseEnabled()) {
            pResult = Proc(this, pData);
        }
    }
    if (pResult == nullptr && m_pVerticalScrollBar != nullptr) {
        if ((uFlags & UIFIND_HITTEST) == 0 || IsMouseEnabled()) {
            pResult = m_pVerticalScrollBar->FindControl(Proc, pData, uFlags);
        }
    }
    if (pResult == nullptr && m_pHorizontalScrollBar != nullptr) {
        if ((uFlags & UIFIND_HITTEST) == 0 || IsMouseEnabled()) {
            pResult = m_pHorizontalScrollBar->FindControl(Proc, pData, uFlags);
        }
    }
    if (pResult != nullptr) {
        return pResult;
    }

    if ((uFlags & UIFIND_HITTEST) == 0 || IsMouseChildEnabled()) {
        RECT rc = m_rcItem;
        rc.left += GetInset().left;
        rc.top += GetInset().top;
        rc.right -= GetInset().right;
        rc.bottom -= GetInset().bottom;
        if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
            rc.right -= m_pVerticalScrollBar->GetFixedWidth();
        }
        if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
            rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
        }
        if ((uFlags & UIFIND_TOP_FIRST) != 0) {
            for (int it = m_items.GetSize() - 1; it >= 0; it--) {
                CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
                if (item1 == nullptr) {
                    continue;
                }
                pResult = item1->FindControl(Proc, pData, uFlags);
                if (pResult != nullptr) {
                    if ((uFlags & UIFIND_HITTEST) != 0 && !pResult->IsFloat() &&
                        !::PtInRect(&rc, *(static_cast<LPPOINT>(pData)))) {
                        continue;
                    } else {
                        return pResult;
                    }
                }
            }
        } else {
            for (int it = 0; it < m_items.GetSize(); it++) {
                CControlUI *item1 = static_cast<CControlUI *>(m_items.GetAt(it));
                if (item1 == nullptr) {
                    continue;
                }
                pResult = item1->FindControl(Proc, pData, uFlags);
                if (pResult != nullptr) {
                    if ((uFlags & UIFIND_HITTEST) != 0 && !pResult->IsFloat() &&
                        !::PtInRect(&rc, *(static_cast<LPPOINT>(pData)))) {
                        continue;
                    } else {
                        return pResult;
                    }
                }
            }
        }
    }

    pResult = nullptr;
    if (pResult == nullptr && (uFlags & UIFIND_ME_FIRST) == 0) {
        if ((uFlags & UIFIND_HITTEST) == 0 || IsMouseEnabled()) {
            pResult = Proc(this, pData);
        }
    }
    return pResult;
}

void CContainerUI::DoPaint(HDC hDC, const RECT &rcPaint)
{
    RECT rcTemp = { 0 };
    if (!::IntersectRect(&rcTemp, &rcPaint, &m_rcItem)) {
        return;
    }

    CRenderClip clip;
    CRenderClip::GenerateClip(hDC, rcTemp, clip);
    CControlUI::DoPaint(hDC, rcPaint);

    if (m_items.GetSize() > 0) {
        RECT rcInset = GetInset();
        RECT rc = m_rcItem;
        rc.left += rcInset.left;
        rc.top += rcInset.top;
        rc.right -= rcInset.right;
        rc.bottom -= rcInset.bottom;
        if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
            if (UICulture::GetInstance()->getDirection() != DIRECTION_RTL)
                rc.right -= m_pVerticalScrollBar->GetFixedWidth();
        }
        if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
            rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
        }

        if (!::IntersectRect(&rcTemp, &rcPaint, &rc)) {
            for (int it = 0; it < m_items.GetSize(); it++) {
                CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
                if (pControl == nullptr) {
                    continue;
                }
                if (!pControl->IsVisible()) {
                    continue;
                }
                if (!::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos())) {
                    continue;
                }
                if (pControl->IsFloat()) {
                    if (!::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos())) {
                        continue;
                    }
                    pControl->DoPaint(hDC, rcPaint);
                }
            }
        } else {
            CRenderClip childClip;
            CRenderClip::GenerateClip(hDC, rcTemp, childClip);
            for (int it = 0; it < m_items.GetSize(); it++) {
                CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(it));
                if (pControl == nullptr) {
                    continue;
                }
                if (!pControl->IsVisible()) {
                    continue;
                }
                if (!::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos())) {
                    continue;
                }
                if (pControl->IsFloat()) {
                    if (!::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos())) {
                        continue;
                    }
                    CRenderClip::UseOldClipBegin(hDC, childClip);
                    pControl->DoPaint(hDC, rcPaint);
                    CRenderClip::UseOldClipEnd(hDC, childClip);
                } else {
                    if (!::IntersectRect(&rcTemp, &rc, &pControl->GetPos())) {
                        continue;
                    }
                    pControl->DoPaint(hDC, rcPaint);
                }
            }
        }
    }

    if (m_pVerticalScrollBar != nullptr && m_pVerticalScrollBar->IsVisible()) {
        if (::IntersectRect(&rcTemp, &rcPaint, &m_pVerticalScrollBar->GetPos())) {
            m_pVerticalScrollBar->DoPaint(hDC, rcPaint);
        }
    }

    if (m_pHorizontalScrollBar != nullptr && m_pHorizontalScrollBar->IsVisible()) {
        if (::IntersectRect(&rcTemp, &rcPaint, &m_pHorizontalScrollBar->GetPos())) {
            m_pHorizontalScrollBar->DoPaint(hDC, rcPaint);
        }
    }
}

void CContainerUI::SetFloatPos(int iIndex)
{
    // 因为CControlUI::SetPos对float的操作影响，这里不能对float组件添加滚动条的影响
    if (iIndex < 0 || iIndex >= m_items.GetSize()) {
        return;
    }

    CControlUI *pControl = static_cast<CControlUI *>(m_items.GetAt(iIndex));
    if (pControl == nullptr) {
        return;
    }

    if (!pControl->IsVisible()) {
        return;
    }
    if (!pControl->IsFloat()) {
        return;
    }

    SIZE szXY = pControl->GetFixedXY();
    SIZE sz = { pControl->GetFixedWidth(), pControl->GetFixedHeight() };
    TPercentInfo rcPercent = pControl->GetFloatPercent();
    LONG width = m_rcItem.right - m_rcItem.left;
    LONG height = m_rcItem.bottom - m_rcItem.top;
    RECT rcCtrl = { 0 };
    rcCtrl.left = (LONG)(width * rcPercent.left) + szXY.cx;
    rcCtrl.top = (LONG)(height * rcPercent.top) + szXY.cy;
    rcCtrl.right = (LONG)(width * rcPercent.right) + szXY.cx + sz.cx;
    rcCtrl.bottom = (LONG)(height * rcPercent.bottom) + szXY.cy + sz.cy;

    if (CDuiString(pControl->GetClass()) == CDuiString(_T("ButtonUI")) ||
        CDuiString(pControl->GetClass()) == CDuiString(_T("RoundedRectButtonUI")) ||
        CDuiString(pControl->GetClass()) == CDuiString(_T("LabelUI"))) {
        SIZE szAvailable = { 0 };
        SIZE szEst = pControl->EstimateSize(szAvailable);

        RECT rcCtrlEst = { 0 };
        rcCtrlEst.left = szXY.cx;
        rcCtrlEst.top = szXY.cy;
        rcCtrlEst.right = szXY.cx + szEst.cx;
        rcCtrlEst.bottom = szXY.cy + szEst.cy;

        pControl->SetPos(rcCtrlEst, false);
        return;
    }
    pControl->SetPos(rcCtrl, false);
}

void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)
{
    if (customScrollBar) {
        if (customScrollBar->ProcessScrollBar(this, rc, cxRequired, cyRequired)) {
            return;
        }
    }

    if (m_pManager == nullptr) {
        return;
    }

    RECT rcScaledPadding = { 0, 0, 0, 0 };
    rcScaledPadding.top = DuiLib::CResourceManager::GetInstance()->Scale(*m_pManager, m_rcScrollBarPadding.top);
    rcScaledPadding.left = DuiLib::CResourceManager::GetInstance()->Scale(*m_pManager, m_rcScrollBarPadding.left);
    rcScaledPadding.bottom = DuiLib::CResourceManager::GetInstance()->Scale(*m_pManager, m_rcScrollBarPadding.bottom);
    rcScaledPadding.right = DuiLib::CResourceManager::GetInstance()->Scale(*m_pManager, m_rcScrollBarPadding.right);

    rc.top += rcScaledPadding.top;
    rc.left += rcScaledPadding.left;
    rc.bottom -= rcScaledPadding.bottom;
    rc.right -= rcScaledPadding.right;
    cyRequired -= (rcScaledPadding.top + rcScaledPadding.bottom);
    cxRequired -= (rcScaledPadding.left + rcScaledPadding.right);

    // by 冰下海 2015/08/16
    while (m_pHorizontalScrollBar) {
        // Scroll needed
        if (cxRequired > rc.right - rc.left && !m_pHorizontalScrollBar->IsVisible()) {
            m_pHorizontalScrollBar->SetVisible(true);
            m_pHorizontalScrollBar->SetScrollRange(cxRequired - (rc.right - rc.left));
            m_pHorizontalScrollBar->SetScrollPos(0);
            SetPos(m_rcItem);
            break;
        }

        // No scrollbar required
        if (!m_pHorizontalScrollBar->IsVisible()) {
            break;
        }

        // Scroll not needed anymore?
        int cxScroll = cxRequired - (rc.right - rc.left);
        if (cxScroll <= 0) {
            m_pHorizontalScrollBar->SetVisible(false);
            m_pHorizontalScrollBar->SetScrollPos(0);
            m_pHorizontalScrollBar->SetScrollRange(0);
            SetPos(m_rcItem);
        } else {
            RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right,
                                    rc.bottom + m_pHorizontalScrollBar->GetFixedHeight() };
            m_pHorizontalScrollBar->SetPos(rcScrollBarPos);

            if (m_pHorizontalScrollBar->GetScrollRange() != cxScroll) {
                int iScrollPos = m_pHorizontalScrollBar->GetScrollPos();
                m_pHorizontalScrollBar->SetScrollRange(::abs(cxScroll)); // if scrollpos>range then scrollpos=range
                if (iScrollPos > m_pHorizontalScrollBar->GetScrollPos()) {
                    SetPos(m_rcItem);
                }
            }
        }
        break;
    }

    while (m_pVerticalScrollBar) {
        // Scroll needed
        if (cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible()) {
            m_pVerticalScrollBar->SetVisible(true);
            m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));
            m_pVerticalScrollBar->SetScrollPos(0);
            SetPos(m_rcItem, false);
            break;
        }

        // No scrollbar required
        if (!m_pVerticalScrollBar->IsVisible()) {
            break;
        }

        // Scroll not needed anymore?
        int cyScroll = cyRequired - (rc.bottom - rc.top);
        if (cyScroll <= 0) {
            m_pVerticalScrollBar->SetVisible(false);
            m_pVerticalScrollBar->SetScrollPos(0);
            m_pVerticalScrollBar->SetScrollRange(0);
            SetPos(m_rcItem, false);
            break;
        }

        RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };

        if (UICulture::GetInstance()->getDirection() == DIRECTION_RTL) {
            rcScrollBarPos = { rc.left, rc.top, rc.left + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };
        }

        m_pVerticalScrollBar->SetPos(rcScrollBarPos, false);

        if (m_pVerticalScrollBar->GetScrollRange() != cyScroll) {
            int iScrollPos = m_pVerticalScrollBar->GetScrollPos();
            m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll)); // if scrollpos>range then scrollpos=range
            if (iScrollPos > m_pVerticalScrollBar->GetScrollPos()) {
                SetPos(m_rcItem, false);
            }
        }
        break;
    }
}

bool CContainerUI::SetSubControlText(LPCTSTR pstrSubControlName, LPCTSTR pstrText)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl != nullptr) {
        pSubControl->SetText(pstrText);
        return TRUE;
    } else {
        return FALSE;
    }
}

bool CContainerUI::SetSubControlFixedHeight(LPCTSTR pstrSubControlName, int cy)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl != nullptr) {
        pSubControl->SetFixedHeight(cy);
        return TRUE;
    } else {
        return FALSE;
    }
}

bool CContainerUI::SetSubControlFixedWdith(LPCTSTR pstrSubControlName, int cx)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl != nullptr) {
        pSubControl->SetFixedWidth(cx);
        return TRUE;
    } else {
        return FALSE;
    }
}

bool CContainerUI::SetSubControlUserData(LPCTSTR pstrSubControlName, LPCTSTR pstrText)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl != nullptr) {
        pSubControl->SetUserData(pstrText);
        return TRUE;
    } else {
        return FALSE;
    }
}

DuiLib::CDuiString CContainerUI::GetSubControlText(LPCTSTR pstrSubControlName)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl == nullptr) {
        return _T("");
    } else {
        return pSubControl->GetText();
    }
}

int CContainerUI::GetSubControlFixedHeight(LPCTSTR pstrSubControlName)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl == nullptr) {
        return -1;
    } else {
        return pSubControl->GetFixedHeight();
    }
}

int CContainerUI::GetSubControlFixedWdith(LPCTSTR pstrSubControlName)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl == nullptr) {
        return -1;
    } else {
        return pSubControl->GetFixedWidth();
    }
}

const CDuiString CContainerUI::GetSubControlUserData(LPCTSTR pstrSubControlName)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = this->FindSubControl(pstrSubControlName);
    if (pSubControl == nullptr) {
        return _T("");
    } else {
        return pSubControl->GetUserData();
    }
}

CControlUI *CContainerUI::FindSubControl(LPCTSTR pstrSubControlName)
{
    CControlUI *pSubControl = nullptr;
    pSubControl = static_cast<CControlUI *>(GetManager()->FindSubControlByName(this, pstrSubControlName));
    return pSubControl;
}
} // namespace DuiLib
